/** @brief Implementación de la clase Directorio
 * @file   Directorio.cpp
 */

#include "Directorio.h"
#include "Archivo.h"
#include <typeinfo>
#include <iostream>
#include <sstream>

/**
 * @brief Constructor por defector
 * @param _nombre string nombre del directorio
 * @param _ruta string ruta que va a tener el directorio
 * @param _fecha string Fecha en que la se creo el directorio
 * @param _usuario Usuario* Puntero al usuario propietario del directorio
 * @param _grupo Grupo* Puntero al grupo que que tendrá acceso al directorio
 * @param _permUsu int Permisos del propietario
 * @param _permGrp int Permisos del grupo
 * @param _permOtros int Permisos de otros
 */
Directorio::Directorio(string _nombre, string _ruta, string _fecha,
        Usuario *_usuario, Grupo *_grupo, int _permUsu, int _permGrp, int _permOtros) :
Recurso(_nombre, _ruta, _fecha, _usuario, _grupo, _permUsu, _permGrp, _permOtros) {
    //Contenido = new Recurso*[_max];
}

/**@brief Constructor de copia*/
Directorio::Directorio(const Directorio& orig) : Recurso(orig) {
    //Contenido = new Recurso*[orig.max];
}

/**
 * @brief Destructor de la clase directorio
 */
Directorio::~Directorio() {
    for (int i = 0; i < Contenido.size(); i++) {
        if (typeid (*(this->Contenido[i])) == typeid (Directorio)) {
                ((Directorio*)Contenido[i])->~Directorio();//si es un directorio se vuelve a llamar al destructor para borrar de forma recursiva
        }else{
            delete Contenido[i]; //si no es un directorio borramos el archivo
        }
    }
}

/**@brief Añade un nuevo recurso al directorio
 * @param rec Recurso* nuevo recurso que se metera en el directorio
 * @pre rec Recurso* debe estar inicializado
 */
void Directorio::addContenido(Recurso* rec) {
    Contenido.push_back(rec);
}

/**@brief Devuelve el vector de contenido del directorio
 * @return vector<Recurso*> vector de punteros a recursos
 */
vector<Recurso*> Directorio::GetContenido() const {
    return Contenido;
}
/**
 * @brief Busca un directorio cuyo nombre coincide con el pasado como parametro
 * @param _nombre string nombre por el que se buscara el directorio
 * @return Directorio* un puntero al directorio encontrado, si no se encuentra el puntero sera 0
 */
Directorio* Directorio::getDirectorio(string _nombre) {
    Directorio* d;
    for (int i = 0; i < Contenido.size(); i++) {
        if (((Contenido.at(i))->GetNombre() ==_nombre) && (typeid(*(Contenido.at(i))) == typeid(Directorio))){
            d = (Directorio*) Contenido.at(i);
        }
    }
    return d;
}

/**
 * @brief Busca un archivo cuyo nombre coincide con el pasado como parametro
 * @param _nombre string nombre por el que se buscara el archivo
 * @return Archivo* un puntero al archivo encontrado, si no se encuentra el puntero sera 0
 */
Archivo* Directorio::getArchivo(string _nombre) {
    Archivo* a;
    for (int i = 0; i < Contenido.size(); i++) {
        if (((Contenido.at(i))->GetNombre() ==_nombre) && (typeid(*(Contenido.at(i))) == typeid(Archivo))){
            a = (Archivo*) Contenido.at(i);
        }
    }
    return a;
}

/**
 * @brief Sustituye el contenido del directorio por el que se le pasa como parametro
 * @param _Contenido vector<Recurso*> vector de punteros a recuros
 */
void Directorio::setContenido(vector<Recurso*> _Contenido) {
    this->Contenido = _Contenido;
}

/** @brief Devuelve un string con las tabulaciones que se mostraran antes del nombre del recurso
 * @param la variable nivel cuenta las tabulaciones necesarias para poder hacer la estructura de arbol 
 * @return string con tabulaciones
 */
string Directorio::tabulador(int nivel) {
    string tab = "";
    stringstream ss;

    for (int i = nivel; i > 0; i--) {
        ss << "|...";
    }
    getline(ss, tab);
    return tab;
}

/** @brief Metodo auxiliar para listarArbol que muestra por pantalla un listado de forma recursiva de el contenido de un directorio
 * @param la variable nivel cuenta las tabulaciones necesarias para poder hacer la estructura de arbol 
 * @pre   nivel se pasa por referencia
 */
void Directorio::arbolAux(int &nivel) {
    cout << tabulador(nivel) <<"+ "<< this->GetNombre() << endl;
    Directorio *d;
    nivel++;
    for (int i = 0; i<this->Contenido.size(); i++) {
        if (typeid (*(this->Contenido[i])) == typeid (Directorio)) {
            /*Llamar al metedodo ls*/
            d = (Directorio*) Contenido[i];
            d->arbolAux(nivel);
        } else {
            cout << tabulador(nivel) <<"- "<< this->Contenido[i]->GetNombre()<< ((Archivo*) Contenido[i])->GetExtension() << endl;
        }
    }
    nivel--;
}

/** @brief Muestra por pantalla un listado en arbol del directorio
 */
void Directorio::listarArbol() {
    int nivel = 1;
    Directorio *d;
    cout<<"----------------------------------"<<endl;
    cout <<"+ "<< this->nombre << endl;
    for (int i = 0; i<this->Contenido.size(); i++) {
        if (typeid (*(this->Contenido[i])) == typeid (Directorio)) {
            /* cout<<tabulador(nivel)<<this->Contenido[i]->GetNombre()<<endl;*/
            d = (Directorio*) Contenido[i];
            d->arbolAux(nivel);
        } else {
            cout << tabulador(nivel) <<"- "<< this->Contenido[i]->GetNombre()<< ((Archivo*) Contenido[i])->GetExtension() << endl;
        }
    }
    cout<<"----------------------------------"<<endl;

}

/**
 * @brief Añade un nuevo recurso al contenido del directorio
 * @param _rec Recurso* puntero a un recurso
 */
void Directorio::addRecurso(Recurso* _rec){
    stringstream ss;
    string r;
    ss<<ruta<<nombre;
    getline(ss,r);
    _rec->SetRuta(r);
    Contenido.push_back(_rec);
}

/**
 * @brief Crea un nuevo archivo y lo mete en el vector de contenido del directorio
 * @param _nombre string nombre del recurso
 * @param _fecha string fecha del recurso
 * @param _size float tamaño del archivo
 * @param _extension string extension del archivo
 * @param _usuario Usuario* puntero al usuario propietario del recurso
 * @param _grupo Grupo* puntero al grupo al que pertenece el recurso
 * @param _permUsu int permisos que tendra el propietario sobre el recurso
 * @param _permGrp int permisos que tendra el grupo sobre el recurso
 * @param _permOtros int permisos que tendran otros sobre el recurso
 * @pre Usuario *_usuario y Grupo *_grupo deben estar inicializados
 */
void Directorio::nuevoArchivo(string _nombre, string _fecha, float _size, string _extension, Usuario *_usuario, Grupo *_grupo, int _permUsu, int _permGrp, int _permOtros) {
    stringstream ss;
    string r;
    ss<<ruta<<nombre;
    getline(ss,r);
    this->Contenido.push_back(new Archivo(_nombre, r, _fecha, _size, _extension, _usuario, _grupo, _permUsu, _permGrp, _permOtros));    
}

/**
 * @brief Crea un nuevo directorio y lo mete en el vector de contenido del directorio
 * @param _nombre string nombre del recurso
 * @param _fecha string fecha del recurso
 * @param _usuario Usuario* puntero al usuario propietario del recurso
 * @param _grupo Grupo* puntero al grupo al que pertenece el recurso
 * @param _permUsu int permisos que tendra el propietario sobre el recurso
 * @param _permGrp int permisos que tendra el grupo sobre el recurso
 * @param _permOtros int permisos que tendran otros sobre el recurso
 * @pre Usuario *_usuario y Grupo *_grupo deben estar inicializados
 */
void Directorio::nuevoDirectorio(string _nombre, string _fecha, Usuario *_usuario, Grupo *_grupo, int _permUsu, int _permGrp, int _permOtros) {
    stringstream ss;
    string r;
    ss<<this->ruta<<nombre;
    getline(ss,r);
    this->Contenido.push_back(new Directorio(_nombre, r, _fecha,_usuario, _grupo, _permUsu, _permGrp, _permOtros));
}

/**
 * @brief Busca un recurso en el contenido del directorio cuyo nombre coincida con el psado como parametro
 * @param nombre string nombre por el que se buscara el recurso
 * @return Recurso* un puntero al recurso encontrado, de no encontrarse el el puntero sera 0
 */
Recurso* Directorio::buscarRecurso(string nombre){
    Recurso* r;
    bool stop=false;
    for(int i=0;i<Contenido.size() && stop==false;i++){
        if(Contenido[i]->GetNombre()==nombre){
            r=Contenido[i];
        }else if(typeid(*Contenido[i])==typeid(Directorio)){
            r=((Directorio*)Contenido[i])->buscarRecurso(nombre);
        }
    }
    
    return r;
}
/**
 * @brief muestra por pantalla un listado de los recursos que contiene el direcotrio con sus permisos
 */
void Directorio::ls(){
    cout<<"----------------------------------"<<endl;
    for(int i=0;i<Contenido.size();i++){
        (*(Contenido.at(i))).verPermisos();
    }
    cout<<"----------------------------------"<<endl;
}
